//---------------------------------------------------------------------------

#ifndef SerialPortThreadH
#define SerialPortThreadH
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include "FIFO8.h"
#include "CommCommand.h"
//---------------------------------------------------------------------------

#define INBUFFER_SIZE       300
#define PENDING_CMD_MAX    16

typedef enum
{
   SERIAL_ERROR_NONE,
   SERIAL_ERROR_PORT_NOT_SET,
   SERIAL_ERROR_BAUD_NOT_SET,
   SERIAL_ERROR_RX_CALLBACK_NOT_SET,
   SERIAL_ERROR_COULD_NOT_OPEN_PORT,
   SERIAL_ERROR_COULD_NOT_SET_TIME_OUTS
} G4_ErrorState_t;

typedef enum
{
   STATE_ATTEMPT_OPEN,
   STATE_OPEN,
   STATE_CLOSED
} G4_State_t;

typedef enum
{
   PAR_NONE,
   PAR_ODD,
   PAR_EVEN
} G4_ParityType_t;

typedef enum
{
    STATE_IDLE,
    STATE_RECEIVE,
    STATE_TIMEOUT
} eTransferState;


class SerialPort : public TThread
{
  typedef struct tagTHREADNAME_INFO
  {
    DWORD dwType;     // must be 0x1000
    LPCSTR szName;    // pointer to name (in user addr space)
    DWORD dwThreadID; // thread ID (-1=caller thread)
    DWORD dwFlags;    // reserved for future use, must be zero
  } THREADNAME_INFO;
private:
   bool ReceiveSet;
   DWORD RxSize;
   DWORD dwBytesRead;
   G4_State_t SerialState;
   HANDLE ComPortHandle;
   COMMTIMEOUTS NewCommTimeouts;
   COMMTIMEOUTS OldCommTimeouts;
   DCB dcbCommPort;
   DWORD LastError;
   char RxBuffer[INBUFFER_SIZE];

   cFIFO8           m_FreeCmd;
   U8               m_FreeCmdStore[PENDING_CMD_MAX];
   cFIFO8           m_PendingCmd;
   U8               m_PendingCmdStore[PENDING_CMD_MAX];
   U8               m_ProcessingCmdHandle;
   cCommCommand     m_CmdData[PENDING_CMD_MAX];
   eTransferState   m_TransferState;

   U8				m_pRxFrameBuff[INBUFFER_SIZE];
   U16				m_RxFrameBuffCnt;
   TDateTime		m_Timeout;


   bool PortOpened(void);
   void SetName(void);
   void CrankStateMachine(void);
   void ClosePort(void);
   void (*ReceiveFunc)(int NumBytes, unsigned char *Buffer);
   char GetParityChar(void);
   
   void ResetBuffer(void);
   void SerialPort::ClearRxBuffer(void);
   void (*SubmitStatus)(cCommCommand* pCmd);
   void TransferStateMachine(void);


protected:
   void __fastcall Execute();
   void __fastcall SerialPort::TransferRxData();
public:
   G4_ErrorState_t Error;
   int PortNumber;
   int BaudRate;
   G4_ParityType_t Parity;
   void Open(void);
   void Close(void);
   void Transmit(int NumBytes, char *OutBuffer);
   void SetupRxCallback(void (*RxCallBackFuncPtr)(int NumBytes, unsigned char *Buffer));
   bool Connected(void);

   bool SubmitCmd(U8 iOp, U8* iBuff, U16 iLen);
   void SetupSubmitStatusCallback(void (*SubmitStatusFuncPtr)(cCommCommand* pCmd));


   __fastcall SerialPort(bool CreateSuspended);
};
//---------------------------------------------------------------------------
#endif
